# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

#Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = (from, to)->
  rest = this.slice((to or from) + 1 or this.length)
  this.length = from < 0 ? this.length + from : from
  return this.push.apply(this, rest)

MY_KEY = 'my'
ENEMY_KEY = 'enemy'

class Battle
  constructor: (@width, @height, @urls)->
    @slimes = {}
    @_holding = null
    @myTurn = true

  update: (mySlimes, enemySlimes) ->
    @slimes[MY_KEY] = mySlimes
    @slimes[ENEMY_KEY] = enemySlimes

  ajaxUpdate: ()->
    self = @

    $.ajax
      url: '/home/slime_datas'
      error: (e)->
        alert('Ajax request error at update_datas')
      success: (data)->
        ((data, callback)->
          mySlimes = JSON.parse(data.my)
          enemySlimes = JSON.parse(data.enemy)          
          callback(mySlimes, enemySlimes)
        )(data, ((m,e)->self.update m, e))

  move: (id, x, y, url = "/home/slime_action") ->
    context = { function: "move",id: id, x: x, y: y }
    @action(context)

  attack: (attacker, target, url = "/home/slime_action")->
    context = { function: "attack", attacker_id: attacker.ID, target_id: target.ID}
    @action(context)

  toBear: (type)->
    @holdObject {item: 'bear', type: type}

  bear: (type, x, y)->
    context = { function: "bear", type: type, x: x, y: y}
    @action(context)

  kill: (slime)->
    context = { function: "kill", id: slime.ID, Side:slime.Side}
    @action(context)

  waitEnemy: (url = "/home/wait") ->
    self = @
    $.ajax
      url: url
      type: 'GET'
      success: (data)->
        if data.ai_end
          self.myTurn = true
          self.clearMsg()
          # setTimeout((-> self.ajaxUpdate()), 200)
          #console.log data.ai_log
          self.ai_log = data.ai_log.reverse()
        if not self.myTurn
          setTimeout((-> self.waitEnemy()), 200)

  endTurn: (url = "/home/end_turn")->
    self = @
    @setMsg("Waiting...")
    @myTurn = false
    $.ajax
      url: url
      type: 'GET'
      success: -> self.waitEnemy()

  action: (context, url = "/home/slime_action")->
    self = @
    $.ajax
      url: url
      type: 'POST'
      data: context
      success: (data)->
        setTimeout((->self.ajaxUpdate()), 200)

  targetAt: (x,y)->
    for t in @enemySlimes
      return t if t.X == x and t.Y == y
    return null

  holdObject: (obj)->
    @_holding = obj
  releaseHoding: -> @_holding = null
  holding: -> @_holding 

  clickEvent: (obj)->
    self = @
    hold = self.holding()
    if obj.item == 'board_block'
      x = obj.obj.x
      y = obj.obj.y
      console.log "x: #{x} y: #{y}"      
      if hold
        if hold.item == 'bear'
          self.bear(hold.type, x, y)
          self.releaseHoding()
        else
          self.move hold.ID, x, y
          self.releaseHoding()
    else if obj.item == 'slime'
      slime = obj.img.slime
      if not hold
        console.log "pickup #{slime}"
        self.holdObject(slime)
      else if hold.item == 'bear'
        self.holdObject slime
      else if hold.item == 'kill'
        self.kill(slime)
        self.releaseHoding()
      else
        if slime.Side != hold.Side
          self.attack hold, slime
          self.releaseHoding()
        else
          self.holdObject slime

  setMsg: (msg)-> @msg = msg
  clearMsg: -> @msg = null

  showLogStep: ->
    self = @
    if (not @ai_log) or @ai_log.length == 0
      return
    act = @ai_log.pop()
    attacker = @slimeWithID(ENEMY_KEY, act.atk_id)
    if attacker == null
      return
    attacker.X = act.x
    attacker.Y = act.y
    if act.target_id >= 0
      target = @slimeWithID(MY_KEY, act.target_id)
      target.HP -= attacker.ATK
      @removeDeadSlime()

  slimeWithID: (side, id)->
    slimes = @slimes[side]
    for slime in slimes
      if slime.ID == id
        return slime
    return null

  removeDeadSlime: ()->
    self = @
    for i in [0...@slimes[MY_KEY].length]
      if @slimes[MY_KEY][i] and @slimes[MY_KEY][i].HP <= 0
        id = @slimes[MY_KEY][i].ID
        @slimes[MY_KEY] = jQuery.grep(self.slimes[MY_KEY], ((slime)-> slime.ID != id))

  setKill: ()->
    @holdObject {item: 'kill'}

      


class Board
  constructor: (@battle, container, contWidth)->
    tileSize = contWidth / @battle.width
    @tile = 
      width:  tileSize
      height: tileSize

    @stage = new Kinetic.Stage
      container: container
      width: @tile.width * @battle.width
      height: @tile.height * @battle.height

    @flags = {}
    @initLayers()

  initLayers: ()->
    @layers = {}
    layerNames = ['base', MY_KEY, ENEMY_KEY, 'msg']
    for n in layerNames
      @layers[n] = new Kinetic.Layer
      @stage.add @layers[n]

  initImages: (imageNames)->
    @images = {}
    @images[MY_KEY] = {}
    @images[ENEMY_KEY] = {}
    self = @    
    for p of @images
      for type, path of imageNames[p]
        (()->
          img = new Image
          img.src = path
          self.images[p][type] = img
        )()

  initBase: ->
    layer = @layers['base']
    battle = @battle
    self = @
    @rects = []

    for i in [0...battle.width]
      @rects.push []
      for j in [0...battle.height]
        ((i,j)->
          rect = new Kinetic.Rect
            x: i * self.tile.width
            y: j * self.tile.height
            width: self.tile.width
            height: self.tile.height
            fill: if (i + j) % 2 == 0 then '#EEE' else '#DDD'

          rect.x = i
          rect.y = j
          rect.on('click', ->
            self.battle.clickEvent { item: 'board_block', obj: rect })

          self.rects[i][j] = rect
          layer.add rect
        )(i, j)

  drawBase: ->
    @layers['base'].draw()

  drawSlimes: (camp) ->
    layer = @layers[camp]
    layer.removeChildren()
    slimes = @battle.slimes[camp]
    images = @images[camp]
    self = @
    SIZE_SCALE_RATE = 0.8

    for slime in slimes
      slime.img = new Kinetic.Image
        x: (slime.X + (1-SIZE_SCALE_RATE)/2) * self.tile.width
        y: (slime.Y + (1-SIZE_SCALE_RATE)/2) * self.tile.height
        image: images[slime.Type] or images['defualt']
        width: self.tile.width * SIZE_SCALE_RATE
        height: self.tile.height * SIZE_SCALE_RATE
      slime.img.slime = slime
      
      ((img, camp) ->
        img.on 'click', ->
          self.battle.clickEvent {item: 'slime', img: img, camp: camp}
      )(slime.img, camp)

      layer.add(slime.img)

      hpText = new Kinetic.Text
        x: slime.X * self.tile.width
        y: (slime.Y + 0.75) * self.tile.height
        text: slime.HP
        fontSize: 16
        fontFamily: 'Calibri'
        fill: 'red'
      layer.add(hpText)
    ###
      slime.hpText = new Kinetic.Text
        x: (slime.X) * @side
        y: (slime.Y + 0.6) * @side
        text: "#{slime.HP}"
        fontSize: 18
        fontFamily: 'Calibri'
        fill: 'red'
      hpLayer.add slime.hpText
    ###
    layer.draw()

  drawMsg: ->
    layer = @layers['msg']
    layer.removeChildren()
    msg = @battle.msg
    if msg
      text = new Kinetic.Text
        x: 0
        y: 0
        text: msg
        fontSize: 40,
        fill: 'black'
      layer.add text

    layer.draw()


  refresh: ->
    @drawSlimes(MY_KEY)
    @drawSlimes(ENEMY_KEY)
    @drawMsg()

clickSlime = (img, camp, board)->
  slime = img.slime
###

  side = slimeWar.board.side
  x = @slime.X
  y = @slime.Y
  range = parseInt(@slime.Range, 10)
  cangos = ((x, y)-> 
    ans = []
    for i in [-range..range]
      for j in [-range..range]
        console.log "i:#{i}, j:#{j}"
        if (Math.abs(i) + Math.abs(j) <= range) and not (i == 0 and j == 0)
          ans.push {x: x+i, y: y+j}
    return ans
  )(x,y)

  for target in cangos
    rect = new Kinetic.Rect
      x: target.x * side
      y: target.y * side
      width: side
      height: side
      fill: 'red'
      opacity: 0.4
    
    rect.attacker = @slime
    rect.target = target
    rect.onClick = ->
      t = slimeWar.battle.targetAt(@target.x, @target.y)
      slimeWar.battle.attack(@attacker, t) if t
    rect.on 'click', rect.onClick
    layer.add rect
  layer.draw()
  setTimeout(
    ()->
      layer.removeChildren()
      layer.draw()
    , 2000)
###

class Game
  constructor: (@board, @fps = 30)->
    @battle = @board.battle

  init: ()->    
    @board.initBase()
    @board.drawBase()
    @battle.update()

  initImages: (imageNames)->
    @board.initImages(imageNames)

  waitTime: ()->
    1000 / @fps

  mainLoop: ->    
    self = @
    if @battle.slimes[MY_KEY] and @battle.slimes[ENEMY_KEY]
      @board.refresh()

    setTimeout((->self.mainLoop()), 500)


slimeWar = Game: Game, Battle:Battle, Board:Board
window.slimeWar = slimeWar
